﻿using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using Cubicle.Excel.Shared;
using ExcelDna.Integration;
using NuGet;

namespace Cubicle.Nuget.Core
{
    public static class NugetExtensions
    {

        public static bool Match(this IPackageRepository repository, string id, string version, out IPackage package)
        {
            package = null;
            SemanticVersion semanticVersion;
            if (!SemanticVersion.TryParse(version, out semanticVersion)) return false;
            package = repository.FindPackage(id, semanticVersion);
            return (package != null);
        }

        public static bool IsInstalled(this IPackageManager manager, string id, string version)
        {
            SemanticVersion semanticVersion;
            if (!SemanticVersion.TryParse(version, out semanticVersion)) return false;
            return manager.LocalRepository.FindPackage(id, semanticVersion) != null;
        }

        public static bool IsInstalled(this IPackageManager manager, string id)
        {
            return manager.LocalRepository.Search(id, false).Count() > 0;
        }

        [Export("InstallPathFunction")]
        public static string XllPath()
        {
            return Path.GetDirectoryName((string)XlCall.Excel(XlCall.xlGetName));
        }

        public static object[,] xlDescriptions(this IEnumerable<IPackage> packages)
        {
            return packages.ToList().ToRange(true);
        }

        public static object[,] xlFiles(this IPackage package)
        {
            return package.GetFiles().ToList().ToRange(true);
        }

        public static object[,] xlDependencies(this IPackage package)
        {
            return package.DependencySets
                .SelectMany(x => x.Dependencies)
                .ToRange(true);
        }

        public static object[,] xlReferences(this IPackage package)
        {
            return package.AssemblyReferences
                .Select(x => x.Name)
                .Union(package.FrameworkAssemblies.Select(x => x.AssemblyName))
                .ToRange(true);
        }

        public static object[,] xlAuthors(this IPackage package)
        {
            return package.Authors.ToRange(true);
        }

        public static bool CheckEquality(string file1, string file2)
        {
            int file1byte;
            int file2byte;
            FileStream fs1;
            FileStream fs2;

            // Check if both files exist
            if (!File.Exists(file1) || !File.Exists(file2))
                return false;

            // Determine if the same file was referenced two times.
            if (file1 == file2)
            {
                // Return true to indicate that the files are the same.
                return true;
            }

            // Open the two files.
            fs1 = new FileStream(file1, FileMode.Open, FileAccess.Read);
            fs2 = new FileStream(file2, FileMode.Open, FileAccess.Read);

            // Check the file sizes. If they are not the same, the files 
            // are not the same.
            if (fs1.Length != fs2.Length)
            {
                // Close the file
                fs1.Close();
                fs2.Close();

                // Return false to indicate files are different
                return false;
            }

            // Read and compare a byte from each file until either a
            // non-matching set of bytes is found or until the end of
            // file1 is reached.
            do
            {
                // Read one byte from each file.
                file1byte = fs1.ReadByte();
                file2byte = fs2.ReadByte();
            }
            while ((file1byte == file2byte) && (file1byte != -1));

            // Close the files.
            fs1.Close();
            fs2.Close();

            // Return the success of the comparison. "file1byte" is 
            // equal to "file2byte" at this point only if the files are 
            // the same.
            return ((file1byte - file2byte) == 0);
        }

    }
}